package com.example.wac.component;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author wuancheng
 * @description
 * @date 2023-05-29 17:48:00
 */

@Slf4j
public class HttpInterceptor extends RestTemplate {

    public HttpInterceptor() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.getObjectMapper().setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // value值为null时不序列化
        converter.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
        List<HttpMessageConverter<?>> converters = getMessageConverters().stream().filter(c -> !(c instanceof MappingJackson2HttpMessageConverter)).collect(Collectors.toList());
        converters.add(converter);
        // 配置http拦截器
        setInterceptors(Collections.singletonList(new AuthInterceptor()));
    }

    public <T> T post(String url, Object body, Class<T> responseType) {
        return post(url, body, null, responseType);
    }

    public <T> T post(String url, Object body, ParameterizedTypeReference<T> responseType) {
        return post(url, body, null, responseType);
    }

    public <T> T post(String url, Object body, HttpHeaders headers, Class<T> responseType) {
        RequestEntity<Object> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
        ResponseEntity<T> resp = exchange(requestEntity, responseType);
        return resp.getBody();
    }

    public <T> T post(String url, Object body, HttpHeaders headers, ParameterizedTypeReference<T> responseType) {
        RequestEntity<Object> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST,  URI.create(url));
        ResponseEntity<T> resp = exchange(requestEntity, responseType);
        return resp.getBody();
    }

    public <T> T get(String url, Object params, Class<T> responseType) {
        return get(url, params, null, responseType);
    }

    public <T> T get(String url, Object params, ParameterizedTypeReference<T> responseType) {
        return get(url, params, null, responseType);
    }

    public <T> T get(String url, Object params, HttpHeaders headers, Class<T> responseType) {
        Map<String, Object> reqMap = new HashMap<>();
        if (params != null) {
            reqMap = JSONUtil.parseObj(params);
        }
        StringBuilder relUrl = new StringBuilder( url);
        if (reqMap != null && !reqMap.isEmpty()) {
            relUrl.append("?").append(addVariables(reqMap));
        }
        RequestEntity<Object> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, null);
        ResponseEntity<T> resp = exchange(relUrl.toString(), HttpMethod.GET, requestEntity, responseType, reqMap);
        return resp.getBody();
    }

    public <T> T get(String url, Object params, HttpHeaders headers, ParameterizedTypeReference<T> responseType) {
        Map<String, Object> reqMap = new HashMap<>();
        if (params != null) {
            reqMap = JSONUtil.parseObj(params);
        }

        StringBuilder relUrl = new StringBuilder(url);
        if (reqMap != null && !reqMap.isEmpty()) {
            relUrl.append("?").append(addVariables(reqMap));
        }
        RequestEntity<Object> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, null);
        ResponseEntity<T> resp = exchange(relUrl.toString(), HttpMethod.GET, requestEntity, responseType, reqMap);
        return resp.getBody();
    }

    private static String addVariables(Map<String, Object> params) {
        StringBuilder sb = new StringBuilder();
        for (String key : params.keySet()) {
            sb.append(key).append("={").append(key).append("}");
            sb.append("&");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }

        return sb.toString();
    }


    /**
     * 拦截器
     */
    class AuthInterceptor implements ClientHttpRequestInterceptor {

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            long st = System.currentTimeMillis();
            // 拦截器中添加请求头等相关信息
            request.getHeaders().add( "Accept", "application/json");

            String bodyStr = new String(body);
            log.info("[request ] [{}] [url: {}, headers: {}] {}", request.getMethodValue(), request.getURI(), request.getHeaders(), bodyStr);
            ClientHttpResponse resp = execution.execute(request, body);
            long et = System.currentTimeMillis();
            log.info("[response] [{}ms] [url: {}, headers: {}] {}", et - st, request.getURI(), resp.getHeaders(), inputStreamToString(resp));
            return resp;
        }
    }

    private String inputStreamToString(ClientHttpResponse resp) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] byteArray = new byte[1024*4];
        int len;
        while ((len = resp.getBody().read(byteArray)) != -1) {
            byteArrayOutputStream.write(byteArray, 0 ,len);
        }
        return new String(byteArrayOutputStream.toByteArray());
    }
}
